package main

import (
	"context"
	"flag"
	"io"
	"log"
	"time"

	pb "gitee.com/xukeawsl/g-rpc_-test/go_client/calculator"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

var (
	addr = flag.String("addr", "localhost:43089", "the address to connect to")
)

type CalculatorImpl struct {
	c      pb.CalculatorClient
	ctx    context.Context
	cancel context.CancelFunc
}

func NewClient(conn *grpc.ClientConn) *CalculatorImpl {
	impl := new(CalculatorImpl)
	impl.c = pb.NewCalculatorClient(conn)
	impl.ctx, impl.cancel = context.WithTimeout(context.Background(), time.Second)
	return impl
}

// 调用服务端的 Add 函数
func (C *CalculatorImpl) Add(a, b int32) int64 {
	r, err := C.c.Add(C.ctx, &pb.AddRequest{
		A: &a,
		B: &b,
	})
	if err != nil {
		log.Fatalf("could not add: %v", err)
	}
	return r.GetResult()
}

// 调用服务端的 Sum 函数
func (C *CalculatorImpl) Sum(nums []int32) int64 {
	stream, err := C.c.Sum(C.ctx)
	if err != nil {
		log.Fatalf("could not sum: %v", err)
	}
	for _, num := range nums {
		request := &pb.SumRequest{
			Num: &num,
		}
		stream.Send(request)
	}
	response, err := stream.CloseAndRecv()
	if err != nil {
		log.Fatalln("fail to CloseAndRecv Sum", err)
	}
	return response.GetSum()
}

// 调用服务端的 Rank 函数
func (C *CalculatorImpl) Rank(digit int32) (nums []int32) {
	stream, err := C.c.Rank(C.ctx, &pb.RankRequest{Digit: &digit})
	if err != nil {
		log.Fatalf("could not rank: %v", err)
	}
	for {
		response, err := stream.Recv()
		if err == io.EOF {
			return
		}
		if err != nil {
			log.Fatalln("fail to Recv Rank", err)
		}
		nums = append(nums, response.GetDigit())
	}
}

// 调用服务端的 Sort 函数
func (C *CalculatorImpl) Sort(nums []int32) []int32 {
	stream, err := C.c.Sort(C.ctx)
	if err != nil {
		log.Fatalf("could not sort: %v", err)
	}
	for _, num := range nums {
		stream.Send(&pb.SortRequest{
			Num: &num,
		})
	}
	stream.CloseSend()
	idx := 0
	for {
		response, err := stream.Recv()
		if err == io.EOF {
			return nums
		}
		if err != nil {
			log.Fatalln("fail to Recv Sort", err)
		}
		nums[idx] = response.GetNum()
		idx++
	}
}

func main() {
	flag.Parse()

	conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()

	client := NewClient(conn)
	defer client.cancel()

	log.Printf("%d", client.Add(12, 13))

	nums := []int32{12, 12, 12}
	log.Printf("Sum: %d", client.Sum(nums))

	digit := 14
	log.Println("Rank:", client.Rank(int32(digit)))

	nums = []int32{134, 213, 23, 43, 123, 234}
	log.Println("Sort:", client.Sort(nums))
}
